Accelerators in Widget Applications

Keyboard accelerators allow the user to activate menu items or buttons using keyboard key combinations instead of the mouse.

Notes

Specifying Accelerators

The ACCELERATOR keyword assigns a key combination that activates a menu item or button event. The value of the keyword is a case-insensitive string that specifies zero or more modifier keys (Ctrl, Shift, or Alt) and one other key. (For Mac users, special steps must be taken to enable Alt key accelerators—See the section below for details.)

When an accelerator is defined for a menu item, the ACCELERATOR keyword string is automatically displayed next to the menu item value. When an accelerator is defined for a button, the ACCELERATOR keyword string is not displayed. Therefore, for a button, we recommend that you include the accelerator shortcut within the button value or tooltip so that your users are aware of the option.

The following table gives the allowed accelerator key names, and also indicates whether that key requires using one of the Ctrl, Shift, or Alt modifiers:

Accelerator Key String

Requires a Modifier

A–Z

yes

0–9 yes
Backspace, Space, Tab yes
Del or Delete, Down, End, Escape, Home, Insert, Left, Next or PageDown, Prior or PageUp, Return or Enter, Right, Up no

F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24

no

NumPadMultiply, NumPadAdd, NumPadSubtract, NumPadDecimal, NumPadDivide, NumPad0, NumPad1, NumPad2, NumPad3, NumPad4, NumPad5, NumPad6, NumPad7, NumPad8, NumPad9

yes

Note: For the number pad accelerators the user must have the NumLock key activated.

Note: On Windows, Shift plus a number key will not work as an accelerator.

Enabling Alt Key Accelerators on Mac

Two steps are required to enable accelerators that use the Alt key to work with the Mac Command (open-Apple) key:

  1. Create a .Xmodmap file in your home folder and add the following three lines to it:

    clear mod1

    clear mod2

    add mod1 = Meta_L

    When Apple’s X11 program starts, this file will automatically be read, and the Apple key will be mapped to the left Command key, which for IDL’s purposes is the Alt key. (Windows Alt key accelerators are mapped to the Mac Command key, not the Option (alt) key.)

  2. Run your system’s X11 program and change its preferences. Under Input in the X11 Preferences dialog, make sure that the following two items are unchecked:

Note: You must relaunch the X11 program for these changes to take effect.

If you distribute your application to other Mac users, they too will need to have an appropriate .Xmodmap and correct X11 Preferences settings in order for Alt key accelerators to work.

Example

The following simple example creates a variety of WIDGET_BUTTON types with accelerators.

; AcceleratorExample.pro

; Example of using keyboard accelerators.

 

pro acceleratorexample_event, event

WIDGET_CONTROL, event.ID, GET_VALUE = value

PRINT, 'Event on: ', value

IF ( uvalue EQ 'Quit' ) THEN BEGIN

WIDGET_CONTROL, event.TOP, /DESTROY

END

end

 

pro AcceleratorExample

 

tlb = WIDGET_BASE( /ROW, $

MBAR = mbar, TITLE = "Accelerator Example", $

XPAD = 10, YPAD = 10, XOFFSET = 25, YOFFSET = 25 )

 

; Create a menu with accelerators. The accelerator string is

; automatically displayed along with the menu item text.

file = WIDGET_BUTTON( mbar, /MENU, VALUE = "File" )

 

one = WIDGET_BUTTON( file, $

VALUE = "One", ACCELERATOR = "Ctrl+1" )

 

two = WIDGET_BUTTON( file, $

VALUE = "Two", ACCELERATOR = "Ctrl+2" )

 

three = WIDGET_BUTTON( file, $

VALUE = "Three", ACCELERATOR = "Ctrl+3" )

 

quit = WIDGET_BUTTON( file, $

VALUE = "Quit", ACCELERATOR = "Ctrl+Q" )

 

; Create a base with push buttons. Include the accelerator

; text in the button value so users are aware of it.

base = WIDGET_BASE( tlb, /COLUMN, /FRAME )

 

b1 = WIDGET_BUTTON( base, $

VALUE = "Affirmative (Ctrl+Y)", ACCELERATOR = "Ctrl+Y" )

 

b2 = WIDGET_BUTTON( base, $

VALUE = "Negative (Ctrl+N)", ACCELERATOR = "Ctrl+N" )

 

; Create a base with radio buttons.

base = WIDGET_BASE( tlb, /COLUMN, /FRAME, /EXCLUSIVE )

 

b1 = WIDGET_BUTTON( base, $

VALUE = "Owl (Ctrl+O)", ACCELERATOR = "Ctrl+O" )

 

b2 = WIDGET_BUTTON( base, $

VALUE = "Emu (Shift+E)", ACCELERATOR = "Shift+E" )

 

b3 = WIDGET_BUTTON( base, $

VALUE = "Bat (Alt+B)", ACCELERATOR = "Alt+B" )

 

; Create a base with check boxes.

base = WIDGET_BASE( tlb, /COLUMN, /FRAME, /NONEXCLUSIVE )

 

b1 = WIDGET_BUTTON( base, $

VALUE = "Hello (F3)", ACCELERATOR = "F3" )

 

b2 = WIDGET_BUTTON( base, $

VALUE = "Goodbye (F4)", ACCELERATOR = "F4" )

 

; Create the widgets and accept events.

WIDGET_CONTROL, tlb, /REALIZE

XMANAGER, 'acceleratorexample', tlb, /NO_BLOCK

 

IF !VERSION.OS_FAMILY NE 'Windows' THEN BEGIN

text = ['Accelerators on non-menu items are not supported', $

'on this platform.', ' ', $

'Accelerators on menu items work on all platforms.']

void = DIALOG_MESSAGE(text, /INFO)

ENDIF

 

END

Save and run the example. The Output Log window reports which button has been activated using the accelerator.

Disabling Button Widget Accelerators

Keyboard events are intercepted by the accelerators before they are passed along to widgets. This means that a widget will never see a keyboard event that maps to an accelerator. This can be resolved using one of the following methods:

Using IGNORE_ACCELERATORS

The IGNORE_ACCELERATORS keyword is available on the following widgets:

For widgets with a text area, accelerator overrides are active only when focus is on an editable text portion. For the dra widget, accelerator overrides are active when the drawing area has focus. For example, when the focus is on a table cell that cannot be edited, accelerators are still enabled.

Set the IGNORE_ACCELERATORS equal to the text string of a single accelerator, an array containing multiple accelerator strings, or 1 (to ignore all accelerators).

Managing Accelerators Example

The following example shows various ways accelerators can be managed. This example creates several menu items with accelerators. Three text boxes either allow all accelerators, some accelerators or no accelerators to receive keyboard events. Additionally you can select a checkbox to desensitize the Delete menu item. When the menu item is desensitized, the accelerator never receives keyboard events.

PRO manage_accel_event, event

END

 

PRO quit_event, event

WIDGET_CONTROL, event.top, /DESTROY

END

 

PRO menu_event, event

PRINT, WIDGET_INFO( event.id, /UNAME )

END

 

PRO menu_sense_event, event

deleteItem = WIDGET_INFO( event.top, FIND_BY_UNAME ="MenuDel" )

WIDGET_CONTROL, deleteItem, SENSITIVE = event.select

END

 

pro manage_accel

 

; Create the top level base.

tlb = WIDGET_BASE( /COLUMN, MBAR = mbar, XSIZE = 250, /TAB_MODE)

 

; Build the menu bar.

edit= WIDGET_BUTTON( mbar, /MENU, VALUE = "Edit" )

menuDel = WIDGET_BUTTON( edit, VALUE = "Delete", $

UNAME = "MenuDel", ACCELERATOR = "Del", $

EVENT_PRO = "menu_event" )

menuCut = WIDGET_BUTTON( edit, VALUE = "Cut", $

UNAME = "MenuCut", ACCELERATOR = "Ctrl+X", $

EVENT_PRO = "menu_event" )

menuCopy = WIDGET_BUTTON( edit, VALUE = "Copy", $

UNAME = "MenuCopy", ACCELERATOR = "Ctrl+C", $

EVENT_PRO = "menu_event" )

menuPaste = WIDGET_BUTTON( edit, VALUE = "Paste", $

UNAME = "MenuPaste", ACCELERATOR = "Ctrl+V", $

EVENT_PRO = "menu_event" )

menuUndo = WIDGET_BUTTON( edit, VALUE = "Undo", $

UNAME = "MenuUndo", ACCELERATOR = "Ctrl+Z",$

EVENT_PRO = "menu_event" )

quit = WIDGET_BUTTON( edit, VALUE = "Quit", $

ACCELERATOR = "Ctrl+Q", EVENT_PRO = "quit_event" )

 

; Add text boxes with various levels of disabled accelerators.

text1 = WIDGET_TEXT( tlb, /EDITABLE, $

VALUE = "Doesn't use IGNORE_ACCELERATORS." )

text2 = WIDGET_TEXT( tlb, /EDITABLE, $

VALUE = "Receives Delete key and Ctrl+C combinations.", $

IGNORE_ACCELERATORS = [ "Del", "Ctrl+C" ] )

text3 = WIDGET_TEXT( tlb, /EDITABLE, $

VALUE = "Receives all accelerator key combinations.", $

IGNORE_ACCELERATORS = 1)

 

; Add a check box to desensitize the Delete menu item.

base2 = WIDGET_BASE( tlb, /FRAME, /NONEXCLUSIVE )

check1 = WIDGET_BUTTON( base2, VALUE = "Menu DEL sensitive", $

EVENT_PRO = "menu_sense_event" )

WIDGET_CONTROL, check1, SET_BUTTON = WIDGET_INFO ( menuDel, $

/SENSITIVE )

 

; Draw the widget.

WIDGET_CONTROL, tlb, /REALIZE

XMANAGER, "manage_accel_event", tlb, /NO_BLOCK

 

END

Compile and run the example. Try highlighting and deleting, or copying and pasting text in each textbox using accelerators defined in the Edit menu. All keyboard events are ineffective (stolen by the accelerators) when the first textbox has focus. The second textbox receives only copy and delete keyboard combinations. The third textbox receives all accelerators. When the delete menu item is desensitized, the Delete key can delete text from all textboxes. The IDL Output Log window prints the name of any menu item that is activated using an accelerator.